home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 22 / Cream of the Crop 22.iso / doom / quake2.zip / TF1_2SRC.ZIP / QUAKE / FORTRESS / SOURCE / COMBAT.QC < prev    next >
Text File  |  1996-09-09  |  10KB  |  465 lines

  1.  
  2. void() T_MissileTouch;
  3. void() info_player_start;
  4. void(entity targ, entity attacker) ClientObituary;
  5.  
  6. void() monster_death_use;
  7.  
  8. // TeamFortress Prototypes
  9. void() tfgoal_activate;
  10.  
  11. //============================================================================
  12.  
  13. /*
  14. ============
  15. CanDamage
  16.  
  17. Returns true if the inflictor can directly damage the target.  Used for
  18. explosions and melee attacks.
  19. ============
  20. */
  21. float(entity targ, entity inflictor) CanDamage =
  22. {
  23. // bmodels need special checking because their origin is 0,0,0
  24.     if (targ.movetype == MOVETYPE_PUSH)
  25.     {
  26.         traceline(inflictor.origin, 0.5 * (targ.absmin + targ.absmax), TRUE, self);
  27.         if (trace_fraction == 1)
  28.             return TRUE;
  29.         if (trace_ent == targ)
  30.             return TRUE;
  31.         return FALSE;
  32.     }
  33.     
  34.     traceline(inflictor.origin, targ.origin, TRUE, self);
  35.     if (trace_fraction == 1)
  36.         return TRUE;
  37.     traceline(inflictor.origin, targ.origin + '15 15 0', TRUE, self);
  38.     if (trace_fraction == 1)
  39.         return TRUE;
  40.     traceline(inflictor.origin, targ.origin + '-15 -15 0', TRUE, self);
  41.     if (trace_fraction == 1)
  42.         return TRUE;
  43.     traceline(inflictor.origin, targ.origin + '-15 15 0', TRUE, self);
  44.     if (trace_fraction == 1)
  45.         return TRUE;
  46.     traceline(inflictor.origin, targ.origin + '15 -15 0', TRUE, self);
  47.     if (trace_fraction == 1)
  48.         return TRUE;
  49.  
  50.     return FALSE;
  51. };
  52.  
  53.  
  54. /*
  55. ============
  56. Killed
  57. ============
  58. */
  59. void(entity targ, entity attacker) Killed =
  60. {
  61.     local entity oself;
  62.     local string db;
  63.  
  64.     oself = self;
  65.     self = targ;
  66.     
  67.     if (self.health < -99)
  68.         self.health = -99;        // don't let sbar look bad if a player
  69.  
  70.     if (self.movetype == MOVETYPE_PUSH || self.movetype == MOVETYPE_NONE)
  71.     {    // doors, triggers, etc
  72.         self.th_die ();
  73.         self = oself;
  74.         return;
  75.     }
  76.  
  77.     self.enemy = attacker;
  78.  
  79. // bump the monster counter
  80.     if (self.flags & FL_MONSTER)
  81.     {
  82.         killed_monsters = killed_monsters + 1;
  83.         WriteByte (MSG_ALL, SVC_KILLEDMONSTER);
  84.     }
  85.  
  86.     ClientObituary(self, attacker);
  87.     
  88.     self.takedamage = DAMAGE_NO;
  89.     self.touch = SUB_Null;
  90.  
  91.     monster_death_use();
  92.     self.th_die ();
  93.     
  94.     self = oself;
  95.     
  96.     if ((toggleflags & TFLAG_RESPAWNDELAY) && (toggleflags & TFLAG_RESPAWNDELAY2))
  97.     {
  98.          self.weaponmode = time + TF_RESPAWNDELAY3;
  99.         db = ftos (TF_RESPAWNDELAY3);
  100.         sprint(self, db);
  101.         sprint(self, " seconds till respawn.\n");
  102.     }
  103.     else if (toggleflags & TFLAG_RESPAWNDELAY)
  104.     {
  105.         self.weaponmode = time + TF_RESPAWNDELAY1;
  106.         db = ftos (TF_RESPAWNDELAY1);
  107.         sprint(self, db);
  108.         sprint(self, " seconds till respawn.\n");
  109.     }
  110.     else if (toggleflags & TFLAG_RESPAWNDELAY2)
  111.     {
  112.         self.weaponmode = time + TF_RESPAWNDELAY2;
  113.         db = ftos (TF_RESPAWNDELAY2);
  114.         sprint(self, db);
  115.         sprint(self, " seconds till respawn.\n");
  116.     }
  117.     else
  118.         self.weaponmode = time;
  119. };
  120.  
  121.  
  122. /*
  123. ============
  124. T_Damage
  125.  
  126. The damage is coming from inflictor, but get mad at attacker
  127. This should be the only function that ever reduces health.
  128. ============
  129. */
  130. void(entity targ, entity inflictor, entity attacker, float damage) T_Damage=
  131. {
  132.     local    vector    dir;
  133.     local    entity    oldself;
  134.     local    float    save;
  135.     local    float    take;
  136.  
  137.     if (!targ.takedamage)
  138.         return;
  139.  
  140. // used by buttons and triggers to set activator for target firing
  141.     damage_attacker = attacker;
  142.  
  143. // check for quad damage powerup on the attacker
  144.     if (attacker.super_damage_finished > time)
  145.         damage = damage * 4;
  146.  
  147. // save damage based on the target's armor level
  148.  
  149.     save = ceil(targ.armortype*damage);
  150.     if (save >= targ.armorvalue)
  151.     {
  152.         save = targ.armorvalue;
  153.         targ.armortype = 0;    // lost all armor
  154.         targ.items = targ.items - (targ.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3));
  155.     }
  156.     
  157.     targ.armorvalue = targ.armorvalue - save;
  158.     take = ceil(damage-save);
  159.  
  160. // add to the damage total for clients, which will be sent as a single
  161. // message at the end of the frame
  162. // FIXME: remove after combining shotgun blasts?
  163.     if (targ.flags & FL_CLIENT)
  164.     {
  165.         targ.dmg_take = targ.dmg_take + take;
  166.         targ.dmg_save = targ.dmg_save + save;
  167.         targ.dmg_inflictor = inflictor;
  168.     }
  169.  
  170. // figure momentum add
  171.     if ( (inflictor != world) && (targ.movetype == MOVETYPE_WALK) )
  172.     {
  173.         dir = targ.origin - (inflictor.absmin + inflictor.absmax) * 0.5;
  174.         dir = normalize(dir);
  175.         targ.velocity = targ.velocity + dir*damage*8;
  176.     }
  177.  
  178. // check for godmode or invincibility
  179.     if (targ.flags & FL_GODMODE)
  180.         return;
  181.     if (targ.invincible_finished >= time)
  182.     {
  183.         if (self.invincible_sound < time)
  184.         {
  185.             sound (targ, CHAN_ITEM, "items/protect3.wav", 1, ATTN_NORM);
  186.             self.invincible_sound = time + 2;
  187.         }
  188.         return;
  189.     }
  190.     
  191. // do the damage
  192.     targ.health = targ.health - take;
  193.             
  194.     if (targ.health <= 0)
  195.     {
  196.         if (inflictor.tfstate & TFSTATE_ALTKILL)
  197.             targ.tfstate = targ.tfstate | TFSTATE_ALTKILL;
  198.         targ.altkillweapon = inflictor.altkillweapon;
  199.         Killed (targ, attacker);
  200.         return;
  201.     }
  202.  
  203. // react to the damage
  204.     oldself = self;
  205.     self = targ;
  206.  
  207.     if ( (self.flags & FL_MONSTER) && attacker != world)
  208.     {
  209.     // get mad unless of the same class (except for soldiers)
  210.         if (self != attacker && attacker != self.enemy)
  211.         {
  212.             if ( (self.classname != attacker.classname) 
  213.             || (self.classname == "monster_army" ) )
  214.             {
  215.                 if (self.enemy.classname == "player")
  216.                     self.oldenemy = self.enemy;
  217.                 self.enemy = attacker;
  218.                 FoundTarget ();
  219.             }
  220.         }
  221.     }
  222.  
  223.     if (self.th_pain)
  224.     {
  225.         self.th_pain (attacker, take);
  226.     // nightmare mode monsters don't go into pain frames often
  227.         if (skill == 3)
  228.             self.pain_finished = time + 5;        
  229.     }
  230.  
  231.     self = oldself;
  232. };
  233.  
  234. /*
  235. ============
  236. TF_T_Damage
  237.  
  238. same thing as above, just with some flags
  239. TF_TD_IGNOREARMOUR: bypasses the armour of the target
  240. TF_TD_NOTTEAM: doesn't damage a team member
  241. TF_TD_NOTSELF: doesn't damage self
  242. ============
  243. */
  244. void(entity targ, entity inflictor, entity attacker, float damage, float T_flags) TF_T_Damage=
  245. {
  246.     local    vector    dir;
  247.     local    entity    oldself;
  248.     local    float    save;
  249.     local    float    take;
  250.  
  251.     if (!targ.takedamage)
  252.         return;
  253.  
  254. // used by buttons and triggers to set activator for target firing
  255.     damage_attacker = attacker;
  256.  
  257. // check for quad damage powerup on the attacker
  258.     if (attacker.super_damage_finished > time)
  259.         damage = damage * 4;
  260.  
  261. // save damage based on the target's armor level
  262.     if (T_flags & TF_TD_IGNOREARMOUR)
  263.     {
  264.         take = damage;
  265.         save = 0;
  266.     }
  267.     else
  268.     {
  269.         save = ceil(targ.armortype*damage);
  270.         if (save >= targ.armorvalue)
  271.         {
  272.             save = targ.armorvalue;
  273.             targ.armortype = 0;    // lost all armor
  274.             targ.items = targ.items - (targ.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3));
  275.         }
  276.     
  277.         targ.armorvalue = targ.armorvalue - save;
  278.         take = ceil(damage-save);
  279.     }
  280.  
  281. // add to the damage total for clients, which will be sent as a single
  282. // message at the end of the frame
  283. // FIXME: remove after combining shotgun blasts?
  284.     if (targ.flags & FL_CLIENT)
  285.     {
  286.         targ.dmg_take = targ.dmg_take + take;
  287.         targ.dmg_save = targ.dmg_save + save;
  288.         targ.dmg_inflictor = inflictor;
  289.     }
  290.  
  291. // figure momentum add
  292.     if ( (inflictor != world) && (targ.movetype == MOVETYPE_WALK) )
  293.     {
  294.         dir = targ.origin - (inflictor.absmin + inflictor.absmax) * 0.5;
  295.         dir = normalize(dir);
  296.         targ.velocity = targ.velocity + dir*damage*8;
  297.     }
  298.  
  299. // check for godmode or invincibility
  300.     if (targ.flags & FL_GODMODE)
  301.         return;
  302.     if (targ.invincible_finished >= time)
  303.     {
  304.         if (self.invincible_sound < time)
  305.         {
  306.             sound (targ, CHAN_ITEM, "items/protect3.wav", 1, ATTN_NORM);
  307.             self.invincible_sound = time + 2;
  308.         }
  309.         return;
  310.     }
  311.  
  312. // team play damage avoidance
  313.     if (T_flags & TF_TD_NOTTEAM)
  314.     {
  315.         if ((teamplay == 1) && (targ.team > 0)&&(targ.team == attacker.team) && (targ != attacker))
  316.             return;
  317.     }
  318.  
  319.     if (T_flags & TF_TD_NOTSELF)
  320.     {
  321.         if (targ == attacker)
  322.             return;
  323.     }
  324.  
  325. // do the damage
  326.     targ.health = targ.health - take;
  327.             
  328.     if (targ.health <= 0)
  329.     {
  330.         if (inflictor.tfstate & TFSTATE_ALTKILL)
  331.             targ.tfstate = targ.tfstate | TFSTATE_ALTKILL;
  332.         targ.altkillweapon = inflictor.altkillweapon;
  333.         Killed (targ, attacker);
  334.         return;
  335.     }
  336.  
  337. // react to the damage
  338.     oldself = self;
  339.     self = targ;
  340.  
  341.     if ( (self.flags & FL_MONSTER) && attacker != world)
  342.     {
  343.     // get mad unless of the same class (except for soldiers)
  344.         if (self != attacker && attacker != self.enemy)
  345.         {
  346.             if ( (self.classname != attacker.classname) 
  347.             || (self.classname == "monster_army" ) )
  348.             {
  349.                 if (self.enemy.classname == "player")
  350.                     self.oldenemy = self.enemy;
  351.                 self.enemy = attacker;
  352.                 FoundTarget ();
  353.             }
  354.         }
  355.     }
  356.  
  357.     if (self.th_pain)
  358.     {
  359.         self.th_pain (attacker, take);
  360.     // nightmare mode monsters don't go into pain frames often
  361.         if (skill == 3)
  362.             self.pain_finished = time + 5;        
  363.     }
  364.  
  365.     self = oldself;
  366. };
  367.  
  368. /*
  369. ============
  370. T_RadiusDamage
  371. ============
  372. */
  373. void(entity inflictor, entity attacker, float damage, entity ignore) T_RadiusDamage =
  374. {
  375.     local    float     points;
  376.     local    entity    head, oldself, oldother;
  377.     local    vector    org;
  378.  
  379.     head = findradius(inflictor.origin, damage+40);
  380.     
  381.     while (head)
  382.     {
  383.         if (head != ignore)
  384.         {
  385.             // Check for TeamFortress Goals that can be triggered by Detpacks
  386.             if (head.classname == "info_tfgoal")
  387.             {
  388.                 if (inflictor.classname == "detpack")
  389.                 {
  390.                     if (head.goal_activation & TFGA_TOUCH_DETPACK)
  391.                     {
  392.                         // Save self and other
  393.                         oldself = self;
  394.                         oldother = other;
  395.                         self = head;
  396.                         other = attacker;
  397.                         tfgoal_activate();    // Attempt to activate the goal
  398.                         self = oldself;
  399.                         other = oldother;
  400.                     }
  401.                 }
  402.             }
  403.             else if (head.takedamage)
  404.             {
  405.                 org = head.origin + (head.mins + head.maxs)*0.5;
  406.                 points = 0.5*vlen (inflictor.origin - org);
  407.                 if (points < 0)
  408.                     points = 0;
  409.                 points = damage - points;
  410.                 if (head == attacker)
  411.                     points = points * 0.5;
  412.                 if (points > 0)
  413.                 {
  414.                     if (CanDamage (head, inflictor))
  415.                     {    // shambler takes half damage from all explosions
  416.                         if (head.classname == "monster_shambler")                        
  417.                             T_Damage (head, inflictor, attacker, points*0.5);
  418.                         else
  419.                             T_Damage (head, inflictor, attacker, points);
  420.                     }
  421.                 }
  422.             }
  423.         }
  424.         head = head.chain;
  425.     }
  426. };
  427.  
  428. /*
  429. ============
  430. T_BeamDamage
  431. ============
  432. */
  433. void(entity attacker, float damage) T_BeamDamage =
  434. {
  435.     local    float     points;
  436.     local    entity    head;
  437.     
  438.     head = findradius(attacker.origin, damage+40);
  439.     
  440.     while (head)
  441.     {
  442.         if (head.takedamage)
  443.         {
  444.             points = 0.5*vlen (attacker.origin - head.origin);
  445.             if (points < 0)
  446.                 points = 0;
  447.             points = damage - points;
  448.             if (head == attacker)
  449.                 points = points * 0.5;
  450.             if (points > 0)
  451.             {
  452.                 if (CanDamage (head, attacker))
  453.                 {
  454.                     if (head.classname == "monster_shambler")                        
  455.                         T_Damage (head, attacker, attacker, points*0.5);
  456.                     else
  457.                         T_Damage (head, attacker, attacker, points);
  458.                 }
  459.             }
  460.         }
  461.         head = head.chain;
  462.     }
  463. };
  464.  
  465.